/************************************************************************************************************************************************
 *   Copyright (C) 2008 by Denjs                                                                                                                *
 *   dplsoft@pisem.net                                                                                                                          *
 *   http://qdroid.berlios.de                                                                                                                   *
 * -----------------------------------------------------------------------                                                                      *
 *   This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or (at your option) any later version.                                      *
 *   This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.                                 *
 *   You should have received a copy of the GNU General Public License along with this program; if not, write to the                            *
 *   Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.                                                  *
 * -------------------------------------------------------------------------------------------------------------------------------------------- *
 *     Эта программа является свободным программным обеспечением; вы можете распространять её и/или модифицировать в соответствии с лицензией   *
 *   GNU General Public License  (УНИВЕРСАЛЬНАЯ ОБЩЕСТВЕННАЯ ЛИЦЕНЗИЯ GNU) версии 2.0 или более поздней - на ваш выбор.                         *
 *     Эта программа распространяется  в надежде что она будет вам полезна, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, подразумеваемых или явных; без обещаний *
 *   полезности или применимости в конкретных условиях. Вы используете  данное ПО на свой страх и риск и сами полностью несете                  *
 *   ответственность за последствия. См. GNU General Public License (УНИВЕРСАЛЬНАЯ ОБЩЕСТВЕННАЯ ЛИЦЕНЗИЯ GNU).                                  *
 *     Вы должны получить копию GNU General Public License (УНИВЕРСАЛЬНАЯ ОБЩЕСТВЕННАЯ ЛИЦЕНЗИЯ GNU)с данным ПО; Если этого не случилось,       *
 *   обратитесь в Фонд Свободного Программного Обеспечения :                                                                                    *
 *   Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.                                                  *
 * -------------------------------------------------------------------------------------------------------------------------------------------  *
 * Замечания для территории России: в соответствии с ГК РФ часть 4, начиная использовать данную программу (исполняемые файлы или исходные       *
 * тексты) вы автоматически соглашаетесь с данной лицензией.
 ************************************************************************************************************************************************/

/*

  UTF-8 russian encoded file
  v 2009.09.14_2130
*/
#include "stdInReader.h"

//---------------------------------------------------------------
stdInReader::stdInReader(QObject * parent) : QThread (parent)
 {
        inited=false;
        DebugLevel=0;

        stdInCashMode=false;
        stdin_ReadyRead=false;

 }

//---------------------------------------------------------------
int stdInReader::open(bool _needAllStreams)
 {
   if (inited) return 1;//already opened
   if (DebugLevel>=4) qDebug()<<"CP:stdInReader::init()[0041]";
   inited=false;
   int rez = 0;
//   if (rez==0)
        if (! stdIn.open(stdin, QIODevice::ReadOnly)) 	 rez = -rez-1;
//   if (rez==0)
        if (! stdOut.open(stdout, QIODevice::WriteOnly))  rez = -rez-2;
//   if (rez==0)
        if (! stdErr.open(stdout, QIODevice::WriteOnly))  rez = -rez-4;
   if ( (rez!=0) and (_needAllStreams==true) ) close(true);
     else { inited=true; emit stdReader_Opened(); };
   if (DebugLevel>=4) qDebug()<<"CP:stdInReader::init()[0050]::rez="<<rez;

   return rez;
 };

//---------------------------------------------------------------
void stdInReader::stop()
{
   this->terminate();
};

//---------------------------------------------------------------
int stdInReader::close(bool failedInit)
 {
   this->terminate();//если закрываем потоки, работать нет смысла
   if (DebugLevel>=4) qDebug()<<"CP:stdInReader::reset()[0055]";
   stdIn.close();
   stdOut.close();
   stdErr.close();
   inited=false;
   if (!failedInit)  emit stdReader_Closed();
   return 0;
 };

//-----------------------------------------------------
void stdInReader::run()
 {
   bool toExit=false;
   if (DebugLevel>=4) qDebug()<<"CP:stdInReader::run()[0066]";

    if (!inited) return;
    while ( (!toExit) and (stdIn.error()==0) )//enum... value QFile::NoError
      {
        /*/ while (stdIn.bytesAvailable()==0) //<------- ВНИМАНИЕ! так - НЕ работает... да) QT 4.5
                                            //почему-то пока не начнешь читать, размер буфера не обновится...
                this->msleep(1000);//10 раз в секунду проверять что там нам прислали... думаю достаточно
        //*/
        data=stdIn.read(1); //тут "блокирующее чтение"... потому никаких sleep не надо
        if (stdIn.bytesAvailable()>0)
           data.append(stdIn.read(stdIn.bytesAvailable()));//и только тут буфер покажет сколько нам послупило данных. лол)

        if (stdIn.error()!=0) {toExit=true; continue;};
        if (data.size()==0) {toExit=true; emit stdIn_StreamClosed(); break;};//если ничего не прочли... то вероятно поток закрыт...
                //как например бывает при чтении "встроенного документа" из bash...
                //вываливаемся...
        //if (DebugLevel>=4)
        //	qDebug()<<"CP:stdInReader::run()[0085]::stdIn.error()"<<stdIn.error();


        if (DebugLevel>=4) qDebug()<<"CP:stdInReader::run()[0080]:(processing in progress...)";
        //emit received_StdIn(data);
        from_stdin_buffer(data);//а там уже сами решат, что отсылать а что нет

        /*-/
        ////------ далее - демо код для примера ----------
        //// что бы оно заработало - надо stdOut.open... раскомментировать выше...
                stdOut.write(QByteArray().append(QString("[")));
                stdOut.write(data);
                stdOut.write(QByteArray().append(QString("]")));
                stdOut.flush();//отправим сразу...
        // */
      };
    return;
 }
//интерфейсы для запуска есть: слот QTread::start(), terminate ()

//---------------------------------------------------------------
//:private:
void stdInReader::from_stdin_buffer(QByteArray Message)// -> к нему подключен SIGNAL QDroid.rsv_from_std_in
{
 if (DebugLevel>=4) qDebug()<<"CP:t_BaseBot::rsv_from_std_in()[0055]";
 if (stdInCashMode)
     {
        if (stdInCash.size()>maxCashSize)
           {
                emit stdIn_CashOverflow();
           };
        stdInCash.append(Message);
        stdin_ReadyRead=true;
        emit stdIn_readyRead();
     }
    else
     {
        emit stdIn_received(Message);//перешлем его
        stdin_ReadyRead=false;
     };
}

//-----------------------------------------------------
//сделать функции потокобезопасными!
//функция, не слот
QByteArray stdInReader::stdin_Read(int maxSize)// -> к нему подключен SIGNAL QDroid.rsv_from_std_in
{
        QByteArray baRez = stdInCash.left(maxSize);
        stdInCash=stdInCash.mid(maxSize);
        if (stdInCash.size()==0) stdin_ReadyRead=false;
                //пока есть данные - флаг должен быть выставлен
        return baRez;
}

//-----------------------------------------------------
int stdInReader::stdin_GetCashSize()//
{
        return stdInCash.size();
}

//-----------------------------------------------------
//если "да" - то значит есть что читать.
// иначе - таймаут
bool stdInReader::sdtin_waitFirReadyRead(int maxTimeMs)//
{
        bool rez=false;  //TIMER!!!!
        int countdown = maxTimeMs;

        //qDebug()<<"!:"<<countdown;
        if (stdInCashMode) return false;// не тот режим - всегда "нет"

        //qDebug()<<"!::"<<countdown;
        while (!stdin_ReadyRead)
          {
                //QThread::msleep(100);
                sleepMS(100);
                //qDebug()<<"!:::"<<countdown;
                if (countdown<0) return rez;
                countdown=countdown-100;
                QApplication::processEvents();
          };
        rez=stdin_ReadyRead;
        return rez;
}

//-----------------------------------------------------
//спим в millisecinds!
int stdInReader::sleepMS( unsigned int time)
{
        // Linux:
        #if defined (Q_WS_X11)
                        usleep(time*1000);//sleep in millisecinds
        // Win:
        #elif defined (Q_WS_WIN)
                        Sleep(time);//WIN  2008.02.19
        // Mac:
        #elif defined (Q_WS_MAC)
                        // NOT SUPPORTED THIS VERSION
        #else
                        // NOT SUPPORTED THIS VERSION
        #endif
        return 0;
};

//-----------------------------------------------------
int stdInReader::send_StdOut(const QByteArray &_data)
  {
        if (DebugLevel>=4) qDebug()<<"CP:stdInReader::send_StdOut()[0096]";
        int rz=stdOut.write(_data);
        stdOut.flush();
        return rz;
  }

//-----------------------------------------------------
int stdInReader::send_StdErr(const QByteArray &_data)
  {
        if (DebugLevel>=4) qDebug()<<"CP:stdInReader::send_StdErr()[0106]";
        int rz=stdErr.write(_data);
        stdErr.flush();
        return rz;
  }
//---------------------------------------------------------------------
//установить режим кеширования для чтения потока данных
// по умолчанию -  DataFlow
void stdInReader::stdIn_SetCachedMode()
{
        stdInCashMode=true;
        emit stdIn_ChangedCashMode(stdInCashMode);
}
//---------------------------------------------------------------------
//установить режим кеширования для чтения потока данных
// по умолчанию -  DataFlow
void stdInReader::stdIn_SetDataFlowMode()
{
        stdInCashMode=false;
        emit stdIn_ChangedCashMode(stdInCashMode);
}
